package com.tonghl.juc.volatile_study.code;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by tonghl
 */

class  MyData{

    volatile int number=0;//volatile增强线程之间的可见性

    public void  addTo60(){
        this.number=60;
    }

    //请注意,此时的number前面是加了volatile修饰的，volatile是不保证原子性的。
    public     void addplusplus(){
        number++;
    }

    AtomicInteger atomicInteger= new AtomicInteger();

    public  void addMyAtomic(){
        atomicInteger.getAndIncrement();
    }

}

/**
 * 1.验证volatile的可见性
 * 1.1假如int number=0；number变量之前根本没有添加volatile关键字修饰
 *
 * 2.验证volatile不保证原子性
 * 2.1原子性是什么意思？
 *    完整性不可分割，即线程再做某个具体的业务的时候，中间不可以加塞儿或者分割。需要整体完整，要么同时成功，要么同时失败。
 *
 * 2.2 是否保证原子性？--->不保证
 *
 * 2.3 why?
 *
 * 2.4如何解决原子性
 *    *加synchronized
 *    *使用JUC下的AtomicInteger
 */
public class VolatileDemo {

    public  static void main(String[] args) {


        //seeOkByvolatile();

        MyData myData = new MyData();

        for (int i = 1; i <=20 ; i++) {

            new Thread(()->{
                for (int j = 1; j <=1000; j++) {
                    myData.addplusplus();
                    myData.addMyAtomic();

                }
            },String.valueOf(i)).start();

        }

        //需要等待前面20个线程都全部计算完成后，再用main线程取得最终的结果值看是多少。
        while (Thread.activeCount()>2){
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName()+"\t this number value is->"+myData.number);
        System.out.println(Thread.currentThread().getName()+"\t atomicInteger number value is->"+myData.atomicInteger);

    }

    /**
     * 1.1 volatile可以保证可见性，及时通知其他线程，主内存中的值已经被修改。command+option+M 提取方法
     *
     */

    public static void seeOkByvolatile() {
        MyData myData = new MyData();//资源类

        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"\t come in");
            try{ TimeUnit.SECONDS.sleep(3);}catch (InterruptedException e){e.printStackTrace();}
            myData.addTo60();
            System.out.println(Thread.currentThread().getName()+"\t update number value");
        },"AAA").start();

        //第二个线程main线程
        while (myData.number==0){
            //main线程一直在这里循环等待，直到number的值为60
        }
        System.out.println(Thread.currentThread().getName()+"\t mission is over，number value:->"+myData.number);
    }
}
